package com.airlines.crewassignment.controller.linkline;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.groups.Default;

import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.optaplanner.core.api.score.buildin.hardsoft.HardSoftScore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.airlines.base.config.jsr303.EntityUpdateView;
import com.airlines.base.config.jsr303.ValidateUtil;
import com.airlines.base.config.response.ResponseResult;
import com.airlines.base.config.response.ResponseResultBuilder;
import com.airlines.base.entity.dict.Select2;
import com.airlines.common.ListSortUtil;
import com.airlines.crewassignment.constant.CrewConstant;
import com.airlines.crewassignment.domain.Crew;
import com.airlines.crewassignment.domain.DateTimeRange;
import com.airlines.crewassignment.domain.Position;
import com.airlines.crewassignment.entity.crew.CrewInfoForAssign;
import com.airlines.crewassignment.entity.crew.CrewSchedule;
import com.airlines.crewassignment.entity.linkline.LinkLineInfoForAssign;
import com.airlines.crewassignment.entity.ruleverification.RuleVerification;
import com.airlines.crewassignment.service.assign.PilotAssignService;
import com.airlines.crewassignment.service.crew.CrewService;
import com.airlines.crewassignment.service.crew.CrewTaskService;
import com.airlines.crewassignment.service.dict.Select2Service;
import com.airlines.crewassignment.service.linkline.PositionService;
import com.airlines.crewassignment.service.optaplanner.OptaplannerService;
import com.airlines.crewassignment.service.ruleverification.RuleHardCheckService;
import com.airlines.crewassignment.service.ruleverification.RuleSoftCheckService;
import com.airlines.crewassignment.service.ruleverification.RuleVerificationService;

/**
 * @author xxxx
 * @date 2018年5月22日
 * @description 飞行员排班主页面
 */
@RequestMapping("pilotAssign")
@Controller
public class PilotAssignController {
	@Autowired
	private CrewTaskService crewTaskService;
	@Autowired
	private CrewService crewService;
	@Autowired
	private PilotAssignService pilotAssignService;
	@Autowired
	private OptaplannerService optaplannerService;
	@Autowired
	private PositionService positionService;
	@Autowired
	private Select2Service select2Service;
	@Autowired
	private RuleHardCheckService ruleHardCheckService;
	@Autowired
	private RuleSoftCheckService ruleSoftCheckService;
	@Autowired
	private RuleVerificationService ruleVerificationService;

	/**
	 * 机组人员日历页面
	 * 
	 * @param crew
	 * @return
	 */
	@RequestMapping("toSchedulePage")
	public String toSchedulePage(Crew crew, @RequestParam String dutyCode, Model model) {
		model.addAttribute("dutyCode", dutyCode);
		return "pilotAssign/schedulePage";
	}

	/**
	 * 机组排班页面 http://172.16.12.159:8080/pilotAssign/toAssignPage
	 *
	 * @return
	 */
	@RequestMapping("toAssignPage")
	public String toAssignPage(@RequestParam String dutyCode, Model model) {
		model.addAttribute("dutyCode", dutyCode);
		return "pilotAssign/assignPage";
	}

	/**
	 * 每日任务界面 http://172.16.12.159:8080/pilotAssign/toSummaryPage
	 *
	 * @return
	 */
	@RequestMapping("toSummaryPage")
	public String toSummaryPage(@RequestParam String dutyCode, Model model) {
		model.addAttribute("dutyCode", dutyCode);
		return "linkLinePage";
	}

	/**
	 * 任务环页面 http://172.16.12.159:8080/pilotAssign/toTaskPage
	 *
	 * @return
	 */
	@RequestMapping("toVerificationDetailPage")
	public String toVerificationDetailPage(@RequestParam String dutyCode, @RequestParam Date flightDate,
			@RequestParam Integer crewLinkLineNo, Model model) {
		model.addAttribute("dutyCode", dutyCode);
		model.addAttribute("flightDate", flightDate);
		model.addAttribute("crewLinkLineNo", crewLinkLineNo);
		return "pilotAssign/verificationDetailPage";
	}

	/**
	 * 任务环页面 http://172.16.12.159:8080/pilotAssign/toTaskPage
	 *
	 * @return
	 */
	@RequestMapping("toTaskPage")
	public String toTaskPage() {
		return "pilotAssign/taskPage";
	}

	/**
	 * 查询机组人员日历
	 * 
	 * @param startDate
	 * @param endDate
	 * @param workcode
	 * @return
	 */
	@RequestMapping("listSchedule")
	@ResponseBody
	public List<CrewSchedule> listCrewSchedule(Date startDate, Date endDate, String workcode) {
		DateTime endDateTime = new DateTime(endDate).millisOfDay().withMaximumValue();
		DateTimeRange dateTimeRange = new DateTimeRange(startDate, endDateTime.toDate());
		List<CrewSchedule> list = crewTaskService.listCrewSchedule(dateTimeRange, null, workcode);
		return (list);
	}

	/**
	 * 查询所有的机组人员的排版相关的信息
	 * http://172.16.12.159:8080/pilotAssign/listCrewInfoForAssign?flightDate=2018-04-10&dutyCode=C
	 * 
	 * @param flightDate
	 * @return
	 */
	@RequestMapping("listCrewInfoForAssign")
	@ResponseBody
	public List<CrewInfoForAssign> listCrewInfoForAssign(Date flightDate, @RequestParam String dutyCode)
			throws IllegalAccessException, InvocationTargetException {
		List<CrewInfoForAssign> caList = crewService.listCrewInfoForAssign(dutyCode, flightDate);
		return (caList);
	}

	/**
	 * http://172.16.12.159:8080/pilotAssign/getLinkLineDate?flightDate=2018-04-10
	 * 查询所有连线以及号位信息
	 * 
	 * @param flightDate
	 * @return
	 */
	@RequestMapping("getLinkLineDate")
	@ResponseBody
	public List<LinkLineInfoForAssign> getLinkLineDate(Date flightDate, @RequestParam String dutyCode) {
		List<LinkLineInfoForAssign> list = pilotAssignService.listLinkLineInfoForAssign(dutyCode, flightDate);
		ListSortUtil.sort(list, true, "td", "loopName");
		return (list);
	}

	/**
	 * http://172.16.12.159:8080/pilotAssign/autoAssign?flightDateStart=2018-04-10
	 * 自动排班
	 * 
	 * @param flightDateStart
	 * @param flightDateEnd
	 * @return
	 */
	@RequestMapping("autoAssign")
	@ResponseBody
	public ResponseResult<?> autoAssign(Date flightDateStart, Date flightDateEnd) {
		if (flightDateStart == null) {
			return ResponseResultBuilder.errorResult(null, "flightDateStart格式错误", null);
		}
		if (flightDateEnd == null) {
			flightDateEnd = new DateTime(flightDateStart).millisOfDay().withMaximumValue().toDate();
		}

		boolean updateAbleFlag = positionService.updateAbleCheck(flightDateStart);
		if (!updateAbleFlag) {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}

		// 自动排班
		HardSoftScore hardScore = optaplannerService.autoAssignF(new DateTime(flightDateStart),
				new DateTime(flightDateEnd));

		// 客舱排班
		// TO DO ....

		if (hardScore.getHardScore() >= 0) {
			return ResponseResultBuilder.successResult(hardScore, "排班结束");
		} else {
			String errorMessage = "自动排班硬规则得分小于零,hardScore=" + hardScore + "，不应采纳，请重新排班";
			return ResponseResultBuilder.errorResult(hardScore, errorMessage, null);
		}
	}

	/**
	 * 清除已经排班人员
	 * 
	 * @param flightDateStart
	 * @param flightDateEnd
	 * @return
	 */
	@RequestMapping("clear")
	@ResponseBody
	public ResponseResult<String> clear(@RequestParam(required = true) Date flightDate, @RequestParam String dutyCode) {
		boolean updateAbleFlag = positionService.updateAbleCheck(flightDate);
		if (updateAbleFlag) {
			positionService.updatePcodeNull(flightDate, dutyCode);
			return ResponseResultBuilder.successResult(null, "清除机组人员成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	/**
	 * 保存手动排班结果,批量保存
	 * 
	 * @param flightDate
	 * @return
	 */
	// @RequestMapping("saveLinkLineDate")
	// @ResponseBody
	// public ResponseResult<String> saveLinkLineDate(List<LinkLineInfoForAssign>
	// list) {
	// boolean saveFlag = pilotAssignService.save(list);
	// if(saveFlag){
	// return ResponseResultBuilder.successResult(null, "保存成功");
	// }else{
	// return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整",null);
	// }
	// }
	//

	/**
	 * 保存手动排班结果,单个新增
	 * 
	 * @param
	 * @return
	 */
	@RequestMapping("getPosition")
	@ResponseBody
	public ResponseResult<?> getPosition(@RequestParam Date flightDate, @RequestParam Integer crewLinkLineNo,
			@RequestParam String rankNo, @RequestParam String dutyCode) {
		Position position = new Position();
		position.setFlightDate(flightDate);
		position.setCrewLinkLineNo(crewLinkLineNo);
		position.setRankNo(rankNo);
		position.setDutyCode(dutyCode);
		boolean saveFlag = pilotAssignService.save(position);
		if (saveFlag) {
			Position positionNew = positionService.getByPrimaryKey(position.getPositionId());
			return ResponseResultBuilder.successResult(positionNew, "保存成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	/**
	 * 保存手动排班结果,单个新增
	 * 
	 * @param
	 * @return
	 */
	@RequestMapping("savePosition")
	@ResponseBody
	public ResponseResult<?> savePosition(@Valid Position position, BindingResult result,
			HttpServletResponse response) {
		ResponseResult<String> r = ValidateUtil.validateDefault(result, response);
		if (!r.isSuccess()) {
			return r;
		}
		boolean saveFlag = pilotAssignService.save(position);
		if (saveFlag) {
			Position positionNew = positionService.getByPrimaryKey(position.getPositionId());
			return ResponseResultBuilder.successResult(positionNew, "保存成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	/**
	 * 保存手动排班结果,单个修改
	 * 
	 * @param
	 * @return
	 */
	@RequestMapping("updatePosition")
	@ResponseBody
	public ResponseResult<String> updatePosition(
			@Validated({ EntityUpdateView.class, Default.class }) Position position, BindingResult result,
			HttpServletResponse response) {
		ResponseResult<String> r = ValidateUtil.validateDefault(result, response);
		if (!r.isSuccess()) {
			return r;
		}
		boolean saveFlag = pilotAssignService.save(position);
		if (saveFlag) {
			return ResponseResultBuilder.successResult(null, "保存成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	@RequestMapping("deletePosition")
	@ResponseBody
	public ResponseResult<String> deletePosition(int positionId) {
		int count = positionService.deleteByPrimaryKey(positionId);

		if (count > -1) {
			return ResponseResultBuilder.successResult(null, "保存成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	/**
	 * http://172.16.12.159:8080/pilotAssign/confirm?flightDate=2018-04-10
	 * 对某天的排班结果进行确认
	 * 
	 * @param flightDate
	 * @return
	 */
	@RequestMapping("confirm")
	@ResponseBody
	public ResponseResult<String> confirm(@RequestParam(required = true) Date flightDate,
			@RequestParam String dutyCode) {
		boolean saveFlag = pilotAssignService.confirm(dutyCode, flightDate);
		if (saveFlag) {
			return ResponseResultBuilder.successResult(null, "保存成功");
		} else {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}
	}

	/**
	 * 查询飞行员的教检学标志下拉框数据
	 * 
	 * @return
	 */
	@RequestMapping("getTsFlag")
	@ResponseBody
	public List<Select2> getTsFlag(@RequestParam String dutyCode) {
		List<Select2> list = new ArrayList<>();
		if (StringUtils.equals(dutyCode, CrewConstant.DUTY_F)) {
			list = select2Service.getPositionTsFlagF();
		} else if (StringUtils.equals(dutyCode, CrewConstant.DUTY_C)) {
			list = select2Service.getPositionTsFlagC();
		}

		return (list);
	}

	/**
	 * 查询飞行员的检查科目
	 * 
	 * @return
	 */
	@RequestMapping("getCheckThing")
	@ResponseBody
	public List<Select2> getCheckThing() {
		List<Select2> list = select2Service.getPositionCheckThingF();
		return (list);
	}

	// http://172.16.12.159:8080/pilotAssign/ruleCk?flightDate=2018-04-09
	@RequestMapping("ruleCk")
	@ResponseBody
	public List<RuleVerification> ruleCk(Date flightDate) {
		// List<RuleVerification> list = ruleHardCheckService.ruleHardCheckF(flightDate,
		// null);
		DateTime flightDateStart = new DateTime(flightDate);
		DateTime flightDateEnd = flightDateStart.millisOfDay().withMaximumValue();
		List<RuleVerification> list = ruleSoftCheckService.ruleSoftCheckF(flightDateStart, flightDateEnd, null);
		return  (list);
	}

	// http://172.16.12.159:8080/pilotAssign/ruleCkSave?flightDate=2018-04-09
	@RequestMapping("ruleCkSave")
	@ResponseBody
	public Object ruleCkSave(Date flightDate) {
		// List<RuleVerification> list = ruleHardCheckService.ruleHardCheckF(flightDate,
		// null);
		DateTime flightDateStart = new DateTime(flightDate);
		DateTime flightDateEnd = flightDateStart.millisOfDay().withMaximumValue();
		ruleVerificationService.checkAndSaveAssignmentF(flightDateStart, flightDateEnd);
		return  ResponseResultBuilder.successResult() ;
	}

	/**
	 * 重新初始化号位信息
	 * 
	 * @param flightDateStart
	 * @param flightDateEnd
	 * @return
	 */
	@RequestMapping("initPositon")
	@ResponseBody
	public ResponseResult<?> initPositon(String dutyCode, Date flightDateStart, Date flightDateEnd) {
		if (flightDateStart == null) {
			return ResponseResultBuilder.errorResult(null, "flightDateStart格式错误", null);
		}
		if (flightDateEnd == null) {
			flightDateEnd = new DateTime(flightDateStart).millisOfDay().withMaximumValue().toDate();
		}

		boolean updateAbleFlag = positionService.updateAbleCheck(flightDateStart);
		if (!updateAbleFlag) {
			return ResponseResultBuilder.errorResult(null, "该日期下的任务不能调整", null);
		}

		ResponseResult<String> rs = positionService.initPositon(dutyCode, flightDateStart, flightDateEnd);

		if (rs.isSuccess()) {
			return rs;
		} else {
			return ResponseResultBuilder.errorResult();
		}
	}

}
